
package stcu;

import stcu.robjects.*;
import com.nvlled.route.*;

import java.util.*;

public class Group {

    private String groupId;
    protected ObjectRouter router;

    protected String username;
    protected Set<String> whitelist;
    protected Set<String> pending;
    protected Set<String> members;
    private boolean host; 

    private Set<GroupMessage> messageLog;
    private Listener listener;

    // TODO: Change groupId type to int
    protected Group(ObjectRouter router, String gid, String name, boolean host) {
        this.username = name;
        this.groupId = gid;
        this.router = router;
        this.host = host;
        messageLog = new HashSet<GroupMessage>();
        whitelist = new HashSet<String>();
        pending = new HashSet<String>();
        members = new HashSet<String>();
        listener = new Deaf();

        whitelist.add(username);
        members.add(username);
        host = true; // still deciding wether to drop this flag
    }

    public void setListener(Listener listener) {
        if (listener != null) {
            this.listener = listener;
        }
    }

    public Set<String> getMembers() {
        return new HashSet(members);
    }

    public String getId() {
        return groupId;
    }

    public void setFolderPath(String path) {
        // resend file list
    }

    public void leave() {
        // Still deciding what to do if the group creator leaves
        router.deliver(new GroupLeave(username, groupId), groupId);
        // unregister from demux 
    }

    public void listMembers() {
        router.deliver(new MemberList(groupId), groupId);
    }

    public void send(String message) {
        router.deliver(new GroupSend(username, groupId, message), groupId);
    }

    public void addMember(String name) {
        whitelist.add(name);
        if (pending.contains(name)) {
            pending.remove(name);
            router.deliver(new MemberAdd(groupId, name), getMembers());
            router.deliver(new GroupJoin.Status("ok", groupId), name);
            members.add(name);
        }
    }

    public boolean isAllowed(String name) {
        return whitelist.contains(name);
    }

    public void receive(GroupLeave member) {
        if (host) {
            String name = member.getUsername();
            if (name != null && members.contains(name)) {
                router.deliver(new MemberDel(groupId, name), getMembers());
                members.remove(name);
            }
        }
    }

    public void receive(MemberList message) {
        if (host) {
            for (String name: members) {
                router.deliver(new MemberAdd(groupId, name, false), message.getSourceAddress());
            }
        }
    }

    public void receive(GroupMessage message) {
        // TODO: check if object is received from group creator
        messageLog.add(message);
        listener.messageReceived(message);
    }

    public Set<GroupMessage> getMessageLog() {
        return messageLog;
    }

    public void receive(GroupSend message) {
        if (host) {
            String sender = message.getUsername();
            if (members.contains(sender)) {
                router.deliver(new GroupMessage(sender, groupId, message.getText()), getMembers());
            } else {
                // log
            }
        }
    }

    public void receive(MemberAdd member) {
        // TODO: check if object is received from group creator
        members.add(member.getName());
        listener.memberJoined(member);
    }
    public void receive(MemberDel member) {
        members.remove(member.getName());
        listener.memberLeft(member);
    }

    public void receive(GroupJoin request) {
        if (host) {
            String name = request.getUsername();
            long id = request.getId();
            if (true) {
                router.deliver(new GroupJoin.Status(id, "ok", groupId), request.getSourceAddress());
                router.deliver(new MemberAdd(groupId, name), getMembers());
                members.add(name);
                AddressTable table = router.getTable();
                table.store(name, request.getSourceAddress());
            } else {
                pending.add(name);
            }
        }
    }

    public static interface Listener {
        public void messageReceived(GroupMessage message);

        public void memberJoined(MemberAdd member);

        public void memberLeft(MemberDel member);
    }

    // Null pointers are evil. Use this as an initial value for the listener.
    private class Deaf implements Listener {
        public void messageReceived(GroupMessage message){ }

        public void memberJoined(MemberAdd member){ }

        public void memberLeft(MemberDel member){ }
    }
}


